#!/usr/bin/perl -w

########################################################
# 	    SSOO Grupo 06 - 2012, 2° Cuatrimestre		   #
# 			Comando ListarW5.pl                        #
########################################################


# Levanto las variables de ambiente.
$CONFDIR = $ENV{CONFDIR};
$BINDIR = $ENV{BINDIR};
$MAEDIR = $ENV{MAEDIR};
$PROCDIR = $ENV{PROCDIR};
$REPODIR = $ENV{REPODIR};
$ARCHCONF = $CONFDIR . "InstalaW5.conf";
$ARCHPAT = $MAEDIR . "patrones";
$ARCHSIS = $MAEDIR . "sistemas";
$LOGGER_EXE = "perl $BINDIR"."LoguearW5.pl ";
local $comando_log = "ListarW5.pl";

# *************************************************************
# 	Funciones auxiliares relacionadas a la carga de filtros 
#	disponibles en el sistema.
# *************************************************************

# Crea un hash con la información de los sistemas por ID.
# CREA: %sistemas.
sub obtenerSistemasValidos(){
	# Verifica la existencia del archivo de patrones.
	if(-e $ARCHSIS){
		open(SISTEMAS, "< $ARCHSIS") or die 
			"No se pudo abrir archivo de sistemas.\n";
	}
	else{
		`$LOGGER_EXE -e -c=124 -l=$comando_log`;
	}

	# Agrega los pares ID / nombre al hash sistemas.	
	while(my $linea = <SISTEMAS>){
		$linea =~ /^(.*),(.*),.*,.*$/;
		$sistemas{$1} = $2;
	}
	close(PATRONES);
}


# Crea un hash con la información de los patrones por ID.
# CREA: %patrones.
sub obtenerPatronesValidos(){
	# Verifica la existencia del archivo de patrones.
	if(-e $ARCHPAT){
		open(PATRONES, "< $ARCHPAT") or die 
			"No se pudo abrir archivo de patrones.\n";
	}
	else{
		`$LOGGER_EXE -e -c=124 -l=$comando_log`;
	}

	# Agrega los pares ID / patrón al hash patrones.	
	while(my $linea = <PATRONES>){
		$linea =~ /^(.*),'(.*)',.*,.*,.*,.*$/;
		$patrones{$1} = $2;
	}
	close(PATRONES);
}


# Crea un hash con los nombres de todos los archivos procesados.
# CREA: %archivos.
sub obtenerArchivosValidos(){
	opendir(PROCDIR, $PROCDIR) or die
		"No se pudo abrir directorio de archivos procesados.\n";
	
	# Leo archivos del directorio de procesados...
	my @archivo = readdir(PROCDIR);
	foreach (@archivo){ 
		# ...ignorando archivos que son de resultados.
		if($_ =~ /.*_.*/){
			$archivos{$_} = "";
		}
	}
	close(PROCDIR);
}


# Busca en ARCHCONF el registro SECUENCIA2, que es la que indica
# el número de último ciclo.
# CREA $ultimoCiclo.
sub obtenerUltimoCiclo(){
	# Verifica la existencia del archivo de configuración.
	if(-e $ARCHCONF){
		open(CONFIG, "< $ARCHCONF") or die
			"No se pudo abrir archivo de configuraciones.\n";
	}
	else {
		`$LOGGER_EXE -e -c=124 -l=$comando_log`; 
	}

	# Busca el registro SECUENCIA2 que almacena el último ciclo. 
	while(my $linea = <CONFIG>){
		if($linea =~ /^SECUENCIA2=(.+)$/){
			my @vec = split("=",$linea);
			$ultimoCiclo = $vec[1];
		}
	}
	close(CONFIG);
}


# *************************************************************
# 	Funciones auxiliares relacionadas a la impresión por 
#	pantalla de filtros.
# *************************************************************

# Imprime por pantalla la lista de patrones disponibles.
# USA: %patrones.
sub imprimirPatronesDisponibles(){
	print("Patrones disponibles: \n");
	for my $id (sort {$a <=> $b} keys %patrones){
		print("\t ID: $id - Patrón: $patrones{$id} \n");
	}
	if(scalar(keys(%patrones)) == 0){
		print("\t Ninguno. \n");
	}
}


# Imprime por pantalla la lista de archivos disponibles.
# USA: %archivos.
sub imprimirArchivosDisponibles(){
	print("Archivos disponibles: \n");	
	for my $archivo (sort {$a cmp $b} keys %archivos){
		print("\t $archivo \n");
	}
	if(scalar(keys(%archivos)) == 0){
		print("\t Ninguno. \n");
	}
}


# Imprime por pantalla la lista de sistemas disponibles.
# USA: %sistemas.
sub imprimirSistemasDisponibles(){
	print("Sistemas disponibles: \n");
	for my $id (sort {$a cmp $b} keys %sistemas){
		print("\t ID: $id - Patrón: $sistemas{$id} \n");
	}
	if(scalar(keys(%sistemas)) == 0){
		print("\t Ninguno. \n");
	}
}


# Imprime por pantalla la lista de patrones para filtrar.
# USA: %patrones, %f_patrones.
sub imprimirPatronesFiltrados(){
	imprimirInforme("Patrones filtrados: \n");
	if(scalar(keys(%f_patrones)) == 0){
		imprimirInforme("\t Ninguno. \n");
	}	
	elsif(scalar(keys(%patrones)) == scalar(keys(%f_patrones))){
		imprimirInforme("\t Todos. \n");
	}
	else{
		for my $id (sort {$a <=> $b} keys %f_patrones){
			imprimirInforme("\t ID: $id - Patrón: $patrones{$id} \n");
		}
	}
}


# Imprime por pantalla la lista de archivos para filtrar.
# USA: %archivos, %f_archivos.
sub imprimirArchivosFiltrados(){
	imprimirInforme("Archivos filtrados: \n");
	if(scalar(keys(%f_archivos)) == 0){
		imprimirInforme("\t Ninguno. \n");
	}
	elsif(scalar(keys(%archivos)) == scalar(keys(%f_archivos))){
		imprimirInforme("\t Todos. \n");
	}
	else{
		for my $id (sort {$a cmp $b} keys %f_archivos){
			imprimirInforme("\t $id \n");
		}
	}
}


# Imprime por pantalla la lista de ciclos para filtrar.
# USA: $ultimoCiclo, %f_ciclos.
sub imprimirCiclosFiltrados(){
	imprimirInforme("Ciclos filtrados: \n");
	if(scalar(keys(%f_ciclos)) == 0){
		imprimirInforme("\t Ninguno. \n");
	}	
	elsif(scalar(keys(%f_ciclos)) == $ultimoCiclo){
		imprimirInforme("\t Todos. \n");
	}
	else{
		for my $ciclo (sort {$a <=> $b} keys %f_ciclos){
			imprimirInforme("\t Ciclo $ciclo \n");
		}
	}
}


# Imprime por pantalla la lista de sistemas para filtrar.
# USA: %sistemas, %f_sistemas.
sub imprimirSistemasFiltrados(){
	imprimirInforme("Sistemas filtrados: \n");
	if(scalar(keys(%f_sistemas)) == 0){
		imprimirInforme("\t Ninguno. \n");
	}
	elsif(scalar(keys(%sistemas)) == scalar(keys(%f_sistemas))){
		imprimirInforme("\t Todos. \n");
	}
	else{
		for my $id (sort {$a cmp $b} keys %f_sistemas){
			imprimirInforme("\t ID: $id - Patrón: $sistemas{$id} \n");
		}
	}
}


# *************************************************************
# 	Funciones auxiliares relacionadas al ingreso de filtros.
# *************************************************************

# Función que espera el ingreso numérico del usuario y muestra un mensaje
# de error si el ingreso no es numérico.
sub ingresoNumerico(){
	$selValida = 0;
	while(!$selValida){
		chomp($numero = <STDIN>);
		if($numero =~ /^[0-9]+$/){
			$selValida = 1;
		}
		else{
			print("Selección inválida. Ingrese nuevamente. \n");
		}
	}
	return $numero;
}


# Guía al usuario en el ingreso de patrones para filtrar los resultados. 
# Almacena en el hash %f_patrones los patrones seleccionados para filtrar.
# USA: $rModo, $g, %patrones.
# CREA / ACTUALIZA: %f_patrones.
sub obtenerFiltrosDePatron(){
	imprimirPatronesDisponibles();
	# Si el modo de filtado es por patrón, sólo se permite elegir uno.
	# (sólo modo -r)
	if($rModo eq "p"){
		print("Ingrese un ID de patrón: \n");
	} 
	# Sino se pueden elegir varios.
	else{
		print("Ingrese ID de patrones para filtrar;\n");
		print("ingrese * para agregar todos los patrones al filtro; \n");
		print("ingrese entrar para terminar. \n");
	}

	my $finDeIngreso = 0;
	local $agregados = 0;
	while(!$finDeIngreso){
		chomp(my $patron = <STDIN>);
		# Sólo se permite salir con entrar cuando:
		#	- el modo es -g.
		# 	- el modo es -r y se agregaron patrones.
		if(($patron eq "") && ($g || $agregados)){
			$finDeIngreso = 1;
		}
		# Se permite agregar a todos los patrones cuando el modo no es "p".
		elsif(($patron eq "*") && ($rModo ne "p")){
			foreach(keys(%patrones)){
				$f_patrones{$_} = 0;
			}
			$agregados = 1;
		}
		# Si el patrón ya está en el filtro se lo elimina.
		elsif(exists $f_patrones{$patron}){
			delete($f_patrones{$patron});
			print("Se ha eliminado el patrón seleccionado. \n");
			if(scalar(keys(%f_patrones)) == 0){
				$agregados = 0;
			}
		}
		# Si el patrón existe y no está en el filtro se lo agrega.
		elsif(exists $patrones{$patron}){
			$f_patrones{$patron} = 0;
			# El modo -r "p" sólo permite seleccionar un patrón.
			if($rModo eq "p"){
				$finDeIngreso = 1;
			}
			$agregados = 1;
		}
		else{
			print("Patrón especificado inválido. Seleccione nuevamente.\n");
		}
	}
}


# Guía al usuario en el ingreso de nombres de archivo para filtrar los resultados. 
# Almacena en el hash %f_archivos los archivos seleccionados para filtrar.
# USA: $rModo, $g, %archivos.
# CREA / ACTUALIZA: %f_archivos.
sub obtenerFiltrosDeArchivo(){
	imprimirArchivosDisponibles();
	# Si el modo de filtado es por archivo, sólo se permite elegir uno.
	# (sólo modo -r)
	if($rModo eq "a"){
		print("Ingrese un nombre de archivo: \n");
	# En los otros dos modos se pueden elegir más de un patrón.
	}
	else{
		print("Ingrese nombres de archivo para filtrar; \n");
		print("ingrese * para agregar todos los archivos al filtro; \n");
		print("ingrese entrar para terminar.\n");
	}

	my $finDeIngreso = 0;
	local $agregados = 0;
	while(!$finDeIngreso){
		chomp(my $archivo = <STDIN>);
		# Sólo se permite salir con entrar cuando:
		#	- el modo es -g.
		# 	- el modo es -r y se agregaron archivos.
		if(($archivo eq "") && ($g || $agregados)){
			$finDeIngreso = 1;
		}
		# Se permite agregar a todos los archivos cuando el modo no es "a".
		elsif(($archivo eq "*") && ($rModo ne "a")){
			foreach(keys(%archivos)){
				$f_archivos{$_} = 0;
			}
			$agregados = 1;
		}
		# Si el archivo ya está en el filtro se lo elimina.
		elsif(exists $f_archivos{$archivo}){
			delete($f_archivos{$archivo});
			print("Se ha eliminado el archivo seleccionado. \n");
			if(scalar(keys(%f_archivos)) == 0){
				$agregados = 0;
			}
		}
		# Si el archivo existe y no está en el filtro se lo agrega.
		elsif(exists $archivos{$archivo}){
			$f_archivos{$archivo} = 0;
			# El modo -r "a" sólo permite agregar un archivo.
			if($rModo eq "a"){
				$finDeIngreso = 1;
			}
			$agregados = 1;
		}
		else{
			print("Archivo especificado inválido. Seleccione nuevamente.\n");
		}
	}
}


# Guía al usuario en el ingreso de números de ciclo para filtrar los resultados. 
# Almacena en el hash %f_ciclos los archivos seleccionados para filtrar.
# USA: $rModo, $g, $ultimoCiclo.
# CREA / ACTUALIZA: %f_ciclos.
sub obtenerFiltrosDeCiclo(){
	print("Ultimo ciclo procesado: \n\t $ultimoCiclo \n");
	# Si el modo de filtado es por ciclo, sólo se permite elegir uno.
	if($rModo eq "c"){
		print("Ingrese un número de ciclo: \n");
	}
	# En los otros dos modos se pueden elegir más de un ciclo.
	else{
		print("Ingrese números de ciclo para filtrar; \n");
		print("ingrese r para determinar un rango de ciclos; \n");
		print("ingrese * para agregar todos los ciclos al filtro; \n");
		print("ingrese entrar para terminar. \n");
	}
	
	my $finDeIngreso = 0;
	local $agregados = 0;
	while(!$finDeIngreso){
		chomp(my $ciclo = <STDIN>);
		# Sólo se permite salir con entrar cuando:
		#	- el modo es -g.
		# 	- el modo es -r y se agregaron ciclos.
		if(($ciclo eq "") && ($g || $agregados)){
			$finDeIngreso = 1;
		}
		# Se permite agregar a un rango de ciclos cuando el modo no es "c".
		elsif(($ciclo eq "r") && ($rModo ne "c") && ($ultimoCiclo != 1)){
			print("Ingrese el número menor del intervalo de rango de ciclos a filtrar. \n");
			my $min = ingresoNumerico();
			while($min >= $ultimoCiclo || $min == 0){
				print("Selección inválida. Ingrese nuevamente. \n");
				$min = ingresoNumerico();
			}
			print("Ingrese el número mayor del intervalo de rango de ciclos a filtrar. \n");
			print("ultimo ciclo = $ultimoCiclo \n");
			my $max = ingresoNumerico();
			while(($max > $ultimoCiclo) || ($max <= $min)){
				print("Selección inválida. Ingrese nuevamente. \n");
				$max = ingresoNumerico();
			}
			for(my $i = $min; $i <= $max; $i++){
				$f_ciclos{$i} = 0;
			}
			$agregados = 1;
		}
		# Se permite agregar a todos los ciclos cuando el modo no es "c".
		elsif(($ciclo eq "*") && ($rModo ne "c")){
			for(my $i = 1; $i <= $ultimoCiclo; $i++){
				$f_ciclos{$i} = 0;
			}
			$agregados = 1;
		}
		# Si el ciclo ya está en el filtro se lo elimina.
		elsif(exists $f_ciclos{$ciclo}){
			delete($f_ciclos{$ciclo});
			print("Se ha eliminado el ciclo seleccionado. \n");
			if(scalar(keys(%f_ciclos)) == 0){
				$agregados = 0;
			}
		}
		# Verifica que la cadena ingresada sea numérica.
		elsif($ciclo =~ /^[0-9]+$/){
			if(($ciclo > $ultimoCiclo) || ($ciclo <= 0)){
				print("Ciclo especificado inválido. Seleccione nuevamente.\n");
			}
			else{
				$f_ciclos{$ciclo} = 0;
				# El modo -r "c" sólo permite seleccionar un ciclo.
				if($rModo eq "c"){
					$finDeIngreso = 1;
				}
				$agregados = 1;
			}
		}
		else{
			print("Ciclo especificado inválido. Seleccione nuevamente.\n");
		}
	}
}


# Guía al usuario en el ingreso de sistemas para filtrar los resultados. 
# Almacena en el hash %f_sistemas los sistemas seleccionados para filtrar.
# USA: %sistemas.
# CREA / ACTUALIZA: %f_sistemas.
sub obtenerFiltrosDeSistema(){
	imprimirSistemasDisponibles();
	print("Ingrese ID de sistemas para filtrar; \n");
	print("ingrese * para agregar todos los sistemas; \n");
	print("ingrese entrar para terminar. \n");	

	my $finDeIngreso = 0;
	while(!$finDeIngreso){
		chomp(my $sistema = <STDIN>);
		if($sistema eq ""){
			$finDeIngreso = 1;
		}
		elsif($sistema eq "*"){
			foreach(keys(%sistemas)){
				$f_sistemas{$_} = 0;
			}
		}
		elsif(exists $f_sistemas{$sistema}){
			delete($f_sistemas{$sistema});
			print("Se ha eliminado el sistema seleccionado.\n");
		}
		elsif(exists $sistemas{$sistema}){
			$f_sistemas{$sistema} = 0;
		}
		else{
			print("$sistema");
			print("Sistema especificado inválido. Seleccione nuevamente.\n");
		}
	}
}


# *************************************************************
# 	Funciones auxiliares relacionadas a la presentación
#	de resultados encontrados.
# *************************************************************

# Obtiene del archivo de configuración el último descriptor de informe 
# utilizado y actualiza el valor en el archivo.
# CREA: $ultimaSec.
sub obtenerNumeroDeInforme(){
	# Verifica la existencia del archivo de configuración.
	if(-e $ARCHCONF){
		open(CONFIG, "< $ARCHCONF") or die
			"No se pudo abrir archivo de configuraciones.\n";
		my @archConfig;
	}
	
	# Busca el registro SECUENCIA1 que almacena el último ciclo.
	# Además, graba el contenido del archivo de configuración a una lista.
	while(my $linea = <CONFIG>){
		if($linea =~ /^SECUENCIA1=(.*)$/){
			my @vec = split("=",$linea);
			$ultimaSec = $vec[1];
			my $aux = $ultimaSec + 1;
			`setConfigVar.sh SECUENCIA1 $aux`;
			last;
		}
		else{
			push(@archConfig, $linea);	
		}
	}

	# Reemplaza la línea de SECUENCIA.
	my $secNueva = $ultimaSec + 1;
	# busco el nombre del usuario actual ($infoUsuario[0])
	my @infoUsuario = getpwuid($>);
	# busco la hora del sistema
	my @timeData = localtime(time);
	my $mes = $timeData[4] + 1;
	my $anio = $timeData[5] + 1900;	
	my $hora = $timeData[3] . "/" . $mes . "/" . $anio . " " . $timeData[2] . ":" . $timeData[1] . "\n";
	my $nuevaLinea = "SECUENCIA1=" . $secNueva . "=" . $infoUsuario[0] . "=" . "$hora" . "\n";
	push(@archConfig, $nuevaLinea);
	while($linea = <CONFIG>){
		push(@archConfig, $linea);
	}
	close(CONFIG);
	
	# Y graba la lista.
	open(CONFIG, "> $ARCHCONF") or die
			"No se pudo guardar archvio de configuranciones.\n";
	print CONFIG @archConfig;
	close(CONFIG);
}


# Dados los hashes de los filtros con las ocurrencias como valores,
# crea un hash con todos los resultados.
# USA: %f_patrones, %f_archivos, %f_ciclos, %f_sistemas
# CREA: %filtrosPorOcurrencias.
sub unificarFiltros(){
	foreach my $clave (keys %f_patrones){
		my $claveNueva = "p" . $clave;
		$filtrosPorOcurrencias{$claveNueva} = $f_patrones{$clave};
	}
	foreach my $clave (keys %f_archivos){
		$claveNueva = "a" . $clave;
		$filtrosPorOcurrencias{$claveNueva} = $f_archivos{$clave};
	}
	foreach my $clave (keys %f_ciclos){
		$claveNueva = "c" . $clave;
		$filtrosPorOcurrencias{$claveNueva} = $f_ciclos{$clave};
	}
	foreach my $clave (keys %f_sistemas){
		$claveNueva = "s" . $clave;
		$filtrosPorOcurrencias{$claveNueva} = $f_sistemas{$clave};
	}
}


# Imprime por pantalla y también a archivo INFORME si corresponde.
# USA: INFORME, $x.
sub imprimirInforme($){
	if($x && $v){
		print INFORME ($_[0]);
	}
	print($_[0]);
}


# Imprime el tipo de filtro que fue leído.
# USA: $1.
sub imprimirTipo(){ 
	if($1 eq "a"){
		imprimirInforme("Archivo ");
	}
	elsif($1 eq "c"){
		imprimirInforme("Ciclo ");
	}
	elsif($1 eq "s"){
		imprimirInforme("Sistema ");
	}
	elsif($1 eq "p"){
		imprimirInforme("Patrón ");
	}
}


# Función principal del ListarW5 -r. Aplica los filtros obtenidos e
# imprime por pantalla los resultados.
# USA: $x, $f_patrones, $f_ciclos, $f_archivos.
sub rMostrarResultados($){
	if($x){
		my $nombreSalida = $REPODIR . "salida_" . $ultimaSec;
		open(INFORME, "> $nombreSalida") or die
			"No se pudo grabar archivo de informe. \n";
	}
	imprimirInforme("W-FIVE: SISTEMA DE CONSULTAS \n");
	imprimirInforme("Consulta de resultados detallados. \n \n");

	# Imprime los filtros usados.
	$v = 1;
	imprimirInforme("Filtros usados: \n");	
	imprimirPatronesFiltrados();
	imprimirCiclosFiltrados();
	imprimirArchivosFiltrados();
	imprimirInforme("\n\n");

	# Verifico si hay registros para listar.
	my $vacio = 1;

	my @listaDePatrones = keys(%f_patrones);
	foreach(@listaDePatrones){
		# Abre cada archivo de patrón que esté en el filtro.
		my $resultados = $PROCDIR . "resultados." . $_;
		if(-e $resultados){
			open(RESULTADOS, "< $resultados") or die 
				"No se pudo abrir archivo de resultados.\n";
		}
		else{
			`$LOGGER_EXE -e -c=124 -l=$comando_log`; 
			next;
		}
		# Puede que el registro sea de varias líneas, sin embargo la primera
		# es siempre de la forma NUMDECICLO+-#-+NOMARCHIVO+-#-+NREG+-#-+RESULTADO
		# La variable lineaNueva se activa cuando se encuentra un registro que
		# cumple todas las condiciones pedidas y se puede extender.
		my $lineaNueva = 0;
		while(my $linea = <RESULTADOS>){
			if($linea =~ /^([0-9]+)\+-\#-\+(.+)\+-\#-\+[0-9]+\+-\#-\+(.+)$/){
				# regexp: 	$1 = número de ciclo, $2 = nombre de archivo
				#			$3 = mensaje de error.
				my @campos = split('\+-\#-\+', $linea);
				if((exists $f_ciclos{$campos[0]}) && (exists $f_archivos{$campos[1]})){
					$vacio = 0;
					imprimirInforme("$campos[3]");
					$lineaNueva = 1;
				}
				else{
					$lineaNueva = 0;
				}
			}
			elsif($lineaNueva){
				imprimirInforme("$linea \n");
			}
		}	
		close(RESULTADOS);
	}

	if($vacio){
		imprimirInforme("No se encontraron resultados para los filtros especificados. \n");
	}

	if($x){
		close(INFORME);
	}
}


# Función principal de ListarW5 -g. Aplica los filtros obtenidos
# e imprime por pantalla los resutados.
# USA: $x, $f_archivos, $f_ciclos, $f_sistemas, $f_patrones.
sub gMostrarResultados($){
	if($x){
		my $nombreSalida = $REPODIR . "salida_" . $ultimaSec;
		open(INFORME, "> $nombreSalida") or die
			"No se pudo grabar archivo de informe. \n";
	}
	imprimirInforme("W-FIVE: SISTEMA DE CONSULTAS \n");
	imprimirInforme("Consulta de resultados globales. \n \n");

	# Verifico que haya filtros activados.
	if(!scalar(keys(%f_archivos)) && !scalar(keys(%f_ciclos)) &&
	   !scalar(keys(%f_sistemas)) && !scalar(keys(%f_patrones)))
	{
		imprimirInforme("No se especificaron filtros. \n");
		if($x){
			close(INFORME);
		}
		exit 0;
	}

	# Imprime los filtros usados.
	$v = 1;
	imprimirInforme("Filtros usados: \n");	
	imprimirPatronesFiltrados();
	imprimirCiclosFiltrados();
	imprimirArchivosFiltrados();
	imprimirSistemasFiltrados();
	imprimirInforme("\n\n");

	# Leo uno por uno todos los archivos de resultados globales.
	my @listaDePatrones = keys(%patrones);
	foreach(@listaDePatrones){
		my $rglobales = $PROCDIR . "rglobales." . $_;
		if(-e $rglobales){
			open(RESULTADOS, "< $rglobales") or die 
				"No se pudo abrir archivo de resultados.\n";
		}
		else{
			`$LOGGER_EXE -e -c=124 -l=$comando_log`; 
			next;
		}
	
		# Guardo la info en los hashes de filtro, actualizando cantidad
		# de hallazgos.
		while(my $linea = <RESULTADOS>){
			if($linea =~ /^([0-9]+),(.+)_(.+),([0-9]+),.+,.+,.+,.+$/){
				# expreg: 	$1 = nro ciclo; $2 = nombre de sistema,
				#			$3 = fecha de log; $4 = cantidad de hallazgos.
				if(exists $f_patrones{$_}){
					$f_patrones{$_} += $4;
				}
				$nombreDeArchivo = $2 . "_" . $3;
				if(exists $f_archivos{$nombreDeArchivo}){
					$f_archivos{$nombreDeArchivo} += $4;
				}
				if(exists $f_ciclos{$1}){
					$f_ciclos{$1} += $4;
				}
				if(exists $f_sistemas{$2}){
					$f_sistemas{$2} += $4;
				}
			}
		}
	}

	# Ordeno la salida.
	unificarFiltros();
	foreach $filtro (sort{$filtrosPorOcurrencias{$a} <=> $filtrosPorOcurrencias{$b}} 
		keys %filtrosPorOcurrencias)
	{
		push(@valores, $filtrosPorOcurrencias{$filtro});
		push(@claves, $filtro);
	}
	
	# Variable usada para imprimir que no se encontraron resultados.
	$vacio = 1;

	# Y muestro según corresponda.
	my $tamFiltros = scalar(@claves);
	
	if($gModo eq "r"){
		imprimirInforme("Consultas de filtros con entre $gMin y $gMax hallazgos. \n");
		# Al tener la salida ordenada no hace falta iterar sobre todo el vector.
		for(my $i = 0; ($i < $tamFiltros) && ($valores[$i] <= $gMax); $i++){
			$claves[$i] =~ /^(.)(.*)$/;
			if($valores[$i] >= $gMin){
				$vacio = 0;
				imprimirTipo();
				imprimirInforme("$2 \t $valores[$i] ");
				if($valores[$i] == 1){
					imprimirInforme("hallazgo. \n");
				}
				else{
					imprimirInforme("hallazgos. \n");
				}
			}
		}
	}
	elsif($gModo eq "c"){
		imprimirInforme("Consultas de filtros con $gCantidad hallazgos. \n");
		for(my $i = 0; ($i < $tamFiltros) && ($valores[$i] <= $gCantidad); $i++){
			$claves[$i] =~ /^(.)(.*)$/;
			if($valores[$i] == $gCantidad){
				$vacio = 0;
				imprimirTipo();
				imprimirInforme("$2 \t $valores[$i] ");
				if($valores[$i] == 1){
					imprimirInforme("hallazgo. \n");
				}
				else{
					imprimirInforme("hallazgos. \n");
				}
			}
		}		
	}
	else{
		if($gModo eq "e"){
			imprimirInforme("Consultas por menor cantidad de hallazgos. \n");	
		}
		elsif($gModo eq "a"){
			imprimirInforme("Consultas por mayor cantidad de hallazgos. \n");
			@claves = reverse(@claves);
			@valores = reverse(@valores);
		}
		for(my $i = 0; ($i < $tamFiltros) && ($i < $gCantidad); $i++){
			$vacio = 0;
			$claves[$i] =~ /^(.)(.*)$/;
			imprimirTipo();
			imprimirInforme("$2 \t $valores[$i] ");
			if($valores[$i] == 1){
				imprimirInforme("hallazgo. \n");
			}
			else{
				imprimirInforme("hallazgos. \n");
			}
		}
	}

	if($vacio){
		imprimirInforme("No se encontraron resultados para los filtros especificados. \n");
	}

	if($x){
		close(INFORME);
	}
}


# *************************************************************
# 	Funciones auxiliares relacionadas a la selección de  
#	filtros para resultados globales y detallados.
# *************************************************************

# Ejecutado sólo si el usuario invoca a la aplicación con la opción -r.
# Guía al usuario en el ingreso de filtros para listar los resultados 
# de los archivos de resultados detallados "resultados.PAT_ID".
# CREA: $p, $c, $a.
sub rSeleccionarFiltros(){
	# Itera hasta que el usuario seleccione una opción válida.
	my $selvalida = 0;
	print("Selección de filtros: \n");
	print("seleccione p para listar por patrón; \n");
	print("seleccione c para listar por ciclo; \n");
	print("seleccione a para listar por archivo. \n");

	while(!$selvalida){
		print("Ingrese una opción: [p, c, a] \n");
		chomp($rModo = <STDIN>);
	
		if($rModo eq "p"){
			$selvalida = 1;
			obtenerFiltrosDePatron();
			obtenerFiltrosDeCiclo();
			obtenerFiltrosDeArchivo();
		}
		
		elsif($rModo eq "c"){
			$selvalida = 1;	
			obtenerFiltrosDeCiclo();
			obtenerFiltrosDePatron();
			obtenerFiltrosDeArchivo();
		}
		
		elsif($rModo eq "a"){
			$selvalida = 1;
			obtenerFiltrosDeArchivo();
			obtenerFiltrosDePatron();
		}

		else{
			print("Selección inválida, intente nuevamente.\n");
		}
	}
}


# Ejecutado sólo si el usuario invoca a la aplicación con la opción -g.
# Selecciona los filtros para la consulta de hallazgos de resultados globales.
sub gSeleccionarFiltros(){
	my $finDeIngreso = 0;
	while(!$finDeIngreso){
		print("Selección de filtros: \n");
		print("seleccione p para agregar filtros por patrón; \n");
		print("seleccione c para agregar filtros por ciclo; \n");
		print("seleccione a para agregar filtros por archivo; \n");
		print("seleccione s para agregar filtros por sistema; \n");
		print("seleccione v para ver filtros agregados hasta ahora; \n");
		print("seleccione entrar para terminar de filtrar. \n");
		print("Ingrese una opción: [p, c, a, s, f, v, entrar] \n");
		chomp(my $filtro = <STDIN>);
	
		if($filtro eq "p"){
			obtenerFiltrosDePatron();
		}
		
		elsif($filtro eq "c"){
			obtenerFiltrosDeCiclo();
		}
		
		elsif($filtro eq "a"){
			obtenerFiltrosDeArchivo();
		}

		elsif($filtro eq "s"){
			obtenerFiltrosDeSistema();
		}

		elsif($filtro eq "v"){
			imprimirPatronesFiltrados();
			imprimirCiclosFiltrados();
			imprimirArchivosFiltrados();
			imprimirSistemasFiltrados();
			imprimirInforme("\n");
		}

		elsif($filtro eq ""){
			$finDeIngreso = 1;
		}
	
		else{
			print("Selección inválida, intente nuevamente.\n");
		}
	}
}


# Permite al usuario seleccionar el modo de consulta para resultados globales.
# CREA: $gModo = [aen], $gCantidad (si $gModo es a o e).
sub gSeleccionarModo(){
	print("Selección de modo: \n");
	print("seleccione a para mostrar mayor cantidad de hallazgos; \n");
	print("seleccione e para mostrar menor cantidad de hallazgos; \n");
	print("seleccione c para mostrar una cantidad específica de hallazgos; \n");
	print("seleccione r para mostrar un rango de hallazgos. \n");
	my $selValida = 0;
	while(!$selValida){
		print("Ingrese una opción: [a, e, c, r] \n");
		chomp($gModo = <STDIN>);
		if($gModo =~ /^[aerc]$/){
			$selValida = 1;
		} 
		else{
			print("Selección inválida. Ingrese nuevamente. \n");
		}
	}

	if($gModo eq "r"){
		print("Ingrese el número mínimo de hallazgos a mostrar. \n");
		$gMin = ingresoNumerico();
		print("Ingrese el número máximo de hallazgos a mostrar. \n");
		$gMax = ingresoNumerico();
		while($gMax <= $gMin){
			print("Selección inválida. Ingrese nuevamente. \n");
			$gMax = ingresoNumerico();
		}
	}
	elsif($gModo eq "c"){
		print("Ingrese el número de hallazgos a mostrar. \n");
		$gCantidad = ingresoNumerico();
	}
	else{
		print("Ingrese la cantidad de resultados que desea mostrar. \n");
		$gCantidad = ingresoNumerico();
	}
}


# Imprime la ayuda de la función.
sub mostrarAyuda(){
print(" Descripción:\n");
print("	Parte del sistema W-FIVE. Resuelve consultas efectuadas\n");
print("	sobre los archivos de resultados globales y de resultados\n");
print("	detallados, mostrando la salida por stdout.\n");
print("\n");
print("	Argumentos:\n");
print("	-r\n");
print("		la consulta lista resultados extraídos de los archivos\n");
print("		de resulados detallados (resultados.PAT_ID).\n");
print("	-g\n");
print("		la consulta lista resultados extraídos de los archivos\n");
print("		de resultados globales (rglobales.PAT_ID).\n");
print("	-x\n");
print("		además de imprimir la salida por stdout graba el \n");
print("		resultado en REPODIR/salida_xxx, con xxx un descriptor\n");
print("		que identifica unívocamente a cada ejecución del \n");
print("		programa.\n");
print("	-h\n");
print("		muestra la ayuda.\n");
print("	\n");
print("	Los parámetros -g y -r son mutuamente excluyentes.\n");
print("\n");
print(" Salida:\n");
print("	0	en caso de éxito;\n");
print("	-1 	en caso de error.\n");
print("\n");
}

# Obtiene de ARGV los argumentos de llamado.
# CREA: $g, $x, $r.
sub obtenerArgumentos(){
	foreach(@ARGV){
		if($_ eq "-h"){
			mostrarAyuda();	
			exit 0;
		}
		
		elsif($_ eq "-g"){
			$g = 1;
			$rModo = 0;
			$v = 1;
		}
		
		elsif($_ eq "-r"){
			$r = 1;
			$gModo = 0;
			$gCantidad = -1;
			$v = 1;
		}

		elsif($_ eq "-x"){
			obtenerNumeroDeInforme();
			$x = 1;
		}
	}
	
	if($r && $g){
		print "Error: -g y -r son mutuamente excluyentes. Ver ayuda.\n";
		return -1;
	}
}

	
sub main(){
	obtenerArgumentos();
	obtenerPatronesValidos();
	obtenerArchivosValidos();
	obtenerUltimoCiclo();
	if($r){
		`$LOGGER_EXE -m=\"Se inicia la consulta de resultados detallados..\" -i -l=$comando_log`;
		rSeleccionarFiltros();
		rMostrarResultados($x);
		`$LOGGER_EXE -m=\"Se completo la consulta de resultados globales exitosamente.\" -i -l=$comando_log`;
	} 
	elsif($g){
		`$LOGGER_EXE-m=\"Se inicia la consulta de resultados globales..\" -i -l=$comando_log`;
		obtenerSistemasValidos();
		gSeleccionarModo();
		gSeleccionarFiltros();
		gMostrarResultados($x);
		`$LOGGER_EXE -m=\"Se completo la consulta de resultados globales exitosamente.\" -i -l=$comando_log`;
	}
	exit 0;
}


main();
